﻿using UnityEditor;
using UnityEngine;

namespace CWM.Skinn
{
    public static partial class SkinnEditorEx
    {
        public static void RendererImport(
            ModelImporterNormals normalsMode = ModelImporterNormals.Calculate,
            ModelImporterNormalCalculationMode calculationMode = ModelImporterNormalCalculationMode.Unweighted,
            float normalSmoothingAngle = 60f,
            ModelImporterTangents tangentMode = ModelImporterTangents.None)
        {
            foreach (var item in SkinnContext.GetContextItems())
            {
                var context = item.GetComponent<Renderer>();
                if (SkinnEx.IsNullOrNotInAScene(context)) continue;
                if (!SkinnEx.HasSharedMesh(context)) continue;
                if (!SkinnContext.IsVertexCountOkay(context)) continue;

                string operations = "Import";
                operations += normalsMode != ModelImporterNormals.None ? ", Normals" : "";
                operations += tangentMode != ModelImporterTangents.None ? ", Tangents" : "";

                SkinnContext.UndoRecord(context, operations);
                RendererImport(context, normalsMode, calculationMode, normalSmoothingAngle, tangentMode);
            }

            SkinnContext.Finished();
        }

        public static void RendererImport(
            Renderer context,
            ModelImporterNormals normalsMode,
            ModelImporterNormalCalculationMode calculationMode,
            float normalSmoothingAngle,
            ModelImporterTangents tangentMode,
            TransferUV lightMapUV = TransferUV.Off
        )
        {
            if (!SkinnEx.HasSharedMesh(context)) return;

            var meshRender = context.CloneAsMeshRenderer(false) as MeshRenderer;
            var meshFilter = meshRender.GetComponent<MeshFilter>();
            var tempMesh = meshFilter.sharedMesh;
            tempMesh.name = "tempMesh";
            tempMesh.ClearBlendShapes();
            tempMesh.uv2 = null; tempMesh.uv3 = null; tempMesh.uv4 = null;

            meshFilter.ToACSIIFBX();
            var fbx = meshFilter.ToACSIIFBX();
            if (string.IsNullOrEmpty(fbx)) return;
            var assetPath = "Assets/SkinnTempFBX.fbx";
            if (System.IO.File.Exists(assetPath)) AssetDatabase.DeleteAsset(assetPath);
            System.IO.File.WriteAllText(assetPath, fbx);

            SkinnEx.Release(tempMesh);
            SkinnEx.Release(meshFilter.gameObject);

            AssetDatabase.Refresh();

            var importer = ModelImporter.GetAtPath(assetPath) as ModelImporter;
            importer.animationType = ModelImporterAnimationType.None;
            importer.importNormals = normalsMode;
            importer.normalCalculationMode = calculationMode;
            importer.normalSmoothingAngle = normalSmoothingAngle;
            importer.importTangents = tangentMode;
            importer.meshCompression = ModelImporterMeshCompression.Off;
            importer.weldVertices = false;
            importer.materialName = ModelImporterMaterialName.BasedOnMaterialName;

            if (lightMapUV != TransferUV.Off) importer.generateSecondaryUV = true;
            else importer.generateSecondaryUV = false;

            AssetDatabase.WriteImportSettingsIfDirty(assetPath);
            AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUncompressedImport);

            var exported = AssetDatabase.LoadAssetAtPath(assetPath, typeof(GameObject)) as GameObject;
            if (!exported) { Debug.LogError("Failed To Import"); return; }
            var exportedMesh = exported.GetComponentsInChildren<MeshFilter>()[0].sharedMesh;

            int[] mapping;
            if (SkinnEx.VertexMapRepair(exportedMesh, context.GetSharedMesh(), out mapping, 50))
            {
                var normals = new Vector3[mapping.Length];
                var tangents = new Vector4[mapping.Length];
                var uvs = new Vector2[mapping.Length];

                var exportedNormals = exportedMesh.normals;
                var exportedTangents = exportedMesh.tangents;
                var exportedUVs = exportedMesh.uv2;
               
                var copyNormals = normalsMode != ModelImporterNormals.None && !SkinnEx.IsNullOrEmpty(exportedNormals);
                var copyTangent = tangentMode != ModelImporterTangents.None && !SkinnEx.IsNullOrEmpty(exportedTangents);
                var copyUV = lightMapUV != TransferUV.Off && !SkinnEx.IsNullOrEmpty(exportedUVs);

                for (int i = 0; i < mapping.Length; i++)
                {
                    if (copyNormals) normals[i] = exportedNormals[mapping[i]];
                    if (copyTangent) tangents[i] = exportedTangents[mapping[i]];
                    if (copyUV) uvs[i] = exportedUVs[mapping[i]];
                }
                var newMesh = context.GetSharedMesh().Clone() as Mesh;
                if (copyNormals) newMesh.normals = newMesh.GetNormalsSmoothed(normals);
                if (copyTangent) newMesh.tangents = tangents;

                if (copyUV)
                {
                    switch (lightMapUV)
                    {
                        case TransferUV.ApplyToChannel_1: newMesh.uv = uvs; break;
                        case TransferUV.ApplyToChannel_2: newMesh.uv2 = uvs; break;
                        case TransferUV.ApplyToChannel_3: newMesh.uv3 = uvs; break;
                        case TransferUV.ApplyToChannel_4: newMesh.uv4 = uvs; break;
#if UNITY_2018_2_OR_NEWER
                        //case TransferUV.ApplyToChannel_5: newMesh.uv5 = uvs; break;
#endif
                        case TransferUV.Off:
                        default: break;
                    }
                }
                context.SetSharedMesh(newMesh);
            }
            else
            {
                Debug.LogError("VertexMapRepair Failed");
            }

            AssetDatabase.DeleteAsset(assetPath);
        }
    }
}